package com.gmt.iotdemo;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.gmt.iot.SDKHelper;
import com.gmt.iot.bean.api.ApiDeviceInfoData;
import com.gmt.iot.bean.mqtt.AttributeValue;
import com.gmt.iot.bean.mqtt.NewVersionInfo;
import com.gmt.iot.bean.mqtt.PackageVersion;
import com.gmt.iot.config.ConfigOption;
import com.gmt.iot.config.ConfigSet;
import com.gmt.iot.device.DeviceListItem;
import com.gmt.iot.listener.IBindDeviceListener;
import com.gmt.iot.listener.IOTAppListener;
import com.gmt.iot.listener.IOTDeviceListener;
import com.gmt.iot.listener.ISDKLoginListener;
import com.gmt.iot.utils.StringUtils;
import com.gmt.iot.utils.TimerUtil;
import com.gmt.iot.utils.TokenUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends Activity {

    final String TAG = "GMTIOT";

    // client views
    LinearLayout lyClient;
    LinearLayout lyPrevClient;
    EditText etClientId;
    EditText etClientSecret;
    Button btExitApp;
    Button btConfirmClient;
    Button btPrevClient;

    // login views
    LinearLayout lyLogin;
    EditText etPhone;
    EditText etMsgCode;
    Button btConfirm;
    Button btCancel;
    Button btPrevLogin;
    TextView tvGetCode;
    CheckBox ckDebug;
    LinearLayout lyPrevLogin;

    // action views
    LinearLayout lyAction;
    EditText etAttrName;
    EditText etAttrValue;
    TextView etActionLog;
    Button btRead;
    Button btWrite;
    Button btLoginAgain;
    Button btDeviceAgain;

    // device views
    LinearLayout lyDevice;
    EditText etTypeId;
    EditText etDeviceId;
    EditText etModelCode;
    Button btDeviceAuthBind;
    Button btDeviceBind;
    Button btDevicePrev;
    Button btDeviceExit;
    LinearLayout lyDevicePrev;

    // 验证码计数
    int codeCounter = 0;

    // 缓存设备信息
    String deviceId;
    String typeId;
    String modelCode;
    Map<String, AttributeValue> AttrValueStorage = new HashMap<>();

    SDKHelper sdkHelper;

    /**
     * 应用测回调
     */
    IOTAppListener appListener = new IOTAppListener() {
        @Override
        public void onCloudStateChanged(CloudState state) {
            Log.d(TAG, "app - onCloudStateChanged: " + state);
            if (state == CloudState.DeviceStateOnline) {
                Toast.makeText(MainActivity.this, "App上线连云成功", Toast.LENGTH_SHORT).show();
                toDeviceWindow();
            } else {
                Toast.makeText(MainActivity.this, "App上线连云失败", Toast.LENGTH_SHORT).show();
                toLoginWindow();
            }
            showLog(String.format("app cloud state changed: %s", state.toString()));
        }

        @Override
        public void onDeviceListChanged(List<DeviceListItem> devices) {
            Log.d(TAG, "app - onDeviceListChanged: " + JSON.toJSONString(devices));
            showLog(String.format("device list changed: %s", JSON.toJSONString(devices)));
            if (!StringUtils.isEmpty(deviceId)) {
                for (DeviceListItem item : devices) {
                    if (StringUtils.isEqual(item.getDeviceId(), deviceId)) {
                        ConfigSet.setConfigValue(ConfigOption.OptionDeviceId, item.getDeviceId());
                        ConfigSet.setConfigValue(ConfigOption.OptionModelCode, item.getModelCode());
                        ConfigSet.setConfigValue(ConfigOption.OptionTypeId, item.getTypeId());
                        toActionWindow();
                        return;
                    }
                }
            }
        }

        @Override
        public void onDeviceCloudStateChanged(String deviceId, CloudState state) {
            Log.d(TAG, "app - onDeviceCloudStateChanged: " + deviceId + ", " + state);
            showLog(String.format("device cloud state changed: %s, %s", deviceId, state.toString()));
        }

        @Override
        public void onDeviceAttributeChanged(String deviceId, List<AttributeValue> attributes) {
            Log.d(TAG, "app - onDeviceAttributeChanged: " + deviceId + ", " + JSON.toJSONString(attributes));
            showLog(String.format("attribute changed: %s, %s", deviceId, JSON.toJSONString(attributes)));
        }

        @Override
        public void onSubscribeResult(boolean result, String deviceId) {
            Log.d(TAG, "app - onSubscribeResult: " + deviceId + ", " + result);
            showLog(String.format("subscribe: %s, %s", deviceId, result));
        }

        @Override
        public void onPublishResult(boolean result, String deviceId) {
            Log.d(TAG, "app - onPublishResult: " + deviceId + ", " + result);
            showLog(String.format("publish: %s, %s", deviceId, result));
        }
    };

    /**
     * 设备测回调
     */
    IOTDeviceListener devListener = new IOTDeviceListener() {
        @Override
        public void onDeviceCloudStateChanged(String deviceId, DeviceCloudState state) {
            Log.d(TAG, "dev - onDeviceCloudStateChanged: " + deviceId + ", " + state);
            if (state == IOTDeviceListener.DeviceCloudState.DeviceStateOnline) {
                Toast.makeText(MainActivity.this, "设备上线连云成功", Toast.LENGTH_SHORT).show();

                sdkHelper.bindDevice(TokenUtil.getUserToken(), deviceId, typeId, modelCode, new IBindDeviceListener() {
                    @Override
                    public void onSuccess(ApiDeviceInfoData device) {
                        Log.e(TAG, "bindDevice success");
                        Toast.makeText(MainActivity.this, "设备绑定成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(String error) {
                        Log.e(TAG, "bindDevice failure");
                        Toast.makeText(MainActivity.this, "设备绑定失败", Toast.LENGTH_SHORT).show();
                    }
                });
            } else {
                Toast.makeText(MainActivity.this, "设备上线连云失败", Toast.LENGTH_SHORT).show();
                if (sdkHelper.isAppConnected()) {
                    toDeviceWindow();
                }
            }
            showLog(String.format("device cloud state changed: %s, %s", deviceId, state.toString()));
        }

        @Override
        public void onDeviceRead(String deviceId, List<AttributeValue> attributes, String msgId) {
            Log.d(TAG, "dev - onDeviceRead: " + deviceId + ", " + JSON.toJSONString(attributes) + ", " + msgId);
            for (AttributeValue attributeValue : attributes) {
                if (AttrValueStorage.containsKey(attributeValue.getName())) {
                    attributeValue.setValue(AttrValueStorage.get(attributeValue.getName()).getValue());
                }
            }
            sdkHelper.responseDeviceAttribute(attributes, msgId);
        }

        @Override
        public void onDeviceWrite(String deviceId, List<AttributeValue> attributes, String msgId) {
            Log.d(TAG, "dev - onDeviceWrite: " + deviceId + ", " + JSON.toJSONString(attributes) + ", " + msgId);
            for (AttributeValue attributeValue : attributes) {
                AttrValueStorage.put(attributeValue.getName(), attributeValue);
            }
            sdkHelper.responseDeviceAttribute(attributes, msgId);
        }

        @Override
        public void onNewVersion(List<NewVersionInfo> list) {
            Log.d(TAG, "dev - onNewVersion: " + deviceId + ", " + JSON.toJSONString(list));

        }
    };

    private void initSdk() {
        List<PackageVersion> packageVersions = new ArrayList<>(2);
        double longitude = 121.472644;
        double latitude = 31.231706;

//        /**
//         * 设备上的应用版本
//         */
//        PackageVersion appVersion = new PackageVersion();
//        appVersion.setPackageName("com.gmt.dev.app");
//        appVersion.setPlatform("rk3308");
//        appVersion.setVersionCode(100);
//        appVersion.setVersionName("1.00");
//        packageVersions.add(appVersion);
//
//        /**
//         * 设备上的系统固件版本
//         */
//        PackageVersion romVersion = new PackageVersion();
//        romVersion.setPackageName("com.gmt.dev.rom");
//        romVersion.setPlatform("rk3308");
//        romVersion.setVersionCode(100);
//        romVersion.setVersionName("1.00");
//        packageVersions.add(romVersion);

        sdkHelper = SDKHelper.with(getApplicationContext())
                .latitude(latitude) // 设置经度
                .longitude(longitude) // 设置纬度
                .versions(packageVersions)
                .init();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initSdk();
        initView();
    }

    @Override
    protected void onDestroy() {
        sdkHelper.release();
        super.onDestroy();
    }

    private void toDeviceWindow() {
        if (!ConfigSet.getConfigValue(ConfigOption.OptionDeviceId).isEmpty()) {
            lyDevicePrev.setVisibility(View.VISIBLE);
        }
        lyDevice.setVisibility(View.VISIBLE);
        lyAction.setVisibility(View.GONE);
        lyLogin.setVisibility(View.GONE);
        lyClient.setVisibility(View.GONE);
    }

    private void toActionWindow() {
        lyAction.setVisibility(View.VISIBLE);
        lyDevice.setVisibility(View.GONE);
        lyLogin.setVisibility(View.GONE);
        lyClient.setVisibility(View.GONE);
    }

    private void toLoginWindow() {
        if (TokenUtil.isUserTokenValid()) {
            lyPrevLogin.setVisibility(View.VISIBLE);
        }
        lyLogin.setVisibility(View.VISIBLE);
        lyAction.setVisibility(View.GONE);
        lyDevice.setVisibility(View.GONE);
        lyClient.setVisibility(View.GONE);
    }

    private void toClientWindow() {
        String clientId = ConfigSet.getConfigValue(ConfigOption.OptionClientId);
        String clientSecret = ConfigSet.getConfigValue(ConfigOption.OptionClientSecret);
        if (isNumChar(clientId) && isNumChar(clientSecret)) {
            lyPrevClient.setVisibility(View.VISIBLE);
        } else {
            lyPrevClient.setVisibility(View.GONE);
        }
        lyClient.setVisibility(View.VISIBLE);
        lyLogin.setVisibility(View.GONE);
        lyAction.setVisibility(View.GONE);
        lyDevice.setVisibility(View.GONE);
    }

    /**
     * 更严格的判断
     *
     * @param telNum
     * @return
     */
    private boolean isMobileNum(String telNum) {
        Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");
        Matcher m = p.matcher(telNum);
        return m.matches();
    }

    /**
     * 限制英文和数字20个
     *
     * @param s
     * @return
     */
    private boolean isNumChar(String s) {
        Pattern p = Pattern.compile("[A-Za-z0-9]{1,32}");
        Matcher m = p.matcher(s);
        return m.matches();
    }

    private void startGetCode() {
        codeCounter = 10;
        tvGetCode.setEnabled(false);
        TimerUtil.getInstance().startTimer("msgCode", 1000, 10, name -> {
            codeCounter--;
            if (codeCounter == 0) {
                tvGetCode.setText("获取");
                tvGetCode.setEnabled(true);
            } else {
                tvGetCode.setText(String.format("(%d)", codeCounter));
            }
        });
    }

    private void stopGetCode() {
        TimerUtil.getInstance().stopTimer("msgCode");
        tvGetCode.setText("获取");
        tvGetCode.setEnabled(true);
    }

    private void initView() {

        lyClient = findViewById(R.id.ly_client);
        lyPrevClient = findViewById(R.id.ly_prev_client);
        etClientId = findViewById(R.id.client_id_et);
        etClientSecret = findViewById(R.id.client_secret_et);
        btExitApp = findViewById(R.id.client_exit_bt);
        btConfirmClient = findViewById(R.id.client_confirm_bt);
        btPrevClient = findViewById(R.id.client_prev_bt);

        etPhone = findViewById(R.id.login_phone_et);
        etMsgCode = findViewById(R.id.login_message_code_et);
        btConfirm = findViewById(R.id.login_confirm_bt);
        btCancel = findViewById(R.id.login_cancle_bt);
        tvGetCode = findViewById(R.id.login_code_send_tv);
        lyPrevLogin = findViewById(R.id.ly_prev_login);
        btPrevLogin = findViewById(R.id.login_prev_bt);
        lyLogin = findViewById(R.id.ly_login);
        ckDebug = findViewById(R.id.debug_ck);

        lyAction = findViewById(R.id.ly_action);
        etAttrName = findViewById(R.id.action_attr_et);
        etAttrValue = findViewById(R.id.action_value_et);
        btWrite = findViewById(R.id.action_write_bt);
        btRead = findViewById(R.id.action_read_bt);
        btLoginAgain = findViewById(R.id.login_again_bt);
        btDeviceAgain = findViewById(R.id.device_again_bt);
        etActionLog = findViewById(R.id.action_log_et);

        etDeviceId = findViewById(R.id.device_deviceId_et);
        etModelCode = findViewById(R.id.device_modelcode_et);
        etTypeId = findViewById(R.id.device_typeid_et);
        btDeviceBind = findViewById(R.id.device_bind_bt);
        btDeviceAuthBind = findViewById(R.id.device_authbind_bt);
        btDevicePrev = findViewById(R.id.device_prev_bt);
        btDeviceExit = findViewById(R.id.device_bind_exit_bt);
        lyDevicePrev = findViewById(R.id.ly_prev_device);
        lyDevice = findViewById(R.id.ly_device);

        sdkHelper.debugFlag(ckDebug.isChecked());

        ckDebug.setOnCheckedChangeListener((buttonView, isChecked) -> {
            sdkHelper.debugFlag(isChecked);
        });

        tvGetCode.setOnClickListener(v -> {
            String phone = etPhone.getText().toString();
            if (isMobileNum(phone)) {
                startGetCode();
                sdkHelper.loginRequestCode(phone, new ISDKLoginListener() {
                    @Override
                    public void onLoginSuccess(String userToken, String validEndTime) {
                        Toast.makeText(MainActivity.this, "获取验证码成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(String error) {
                        Toast.makeText(MainActivity.this, "获取验证码失败", Toast.LENGTH_SHORT).show();
                    }
                });
            } else {
                Toast.makeText(this, "手机号码非法", Toast.LENGTH_SHORT).show();
            }
        });

        btConfirmClient.setOnClickListener(v -> {
            String clientId = etClientId.getText().toString();
            String clientSecret = etClientSecret.getText().toString();

            if (isNumChar(clientId) && isNumChar(clientSecret)) {
                ConfigSet.setConfigValue(ConfigOption.OptionClientId, clientId);
                ConfigSet.setConfigValue(ConfigOption.OptionClientSecret, clientSecret);
                sdkHelper.clientId(clientId).clientSecret(clientSecret).appConnect(appListener);
                toLoginWindow();
            } else {
                Toast.makeText(this, "输入id非法", Toast.LENGTH_SHORT).show();
            }
        });

        btExitApp.setOnClickListener(v -> {
            finish();
        });

        btPrevClient.setOnClickListener(v -> {
            String clientId = ConfigSet.getConfigValue(ConfigOption.OptionClientId);
            String clientSecret = ConfigSet.getConfigValue(ConfigOption.OptionClientSecret);
            if (isNumChar(clientId) && isNumChar(clientSecret)) {
                etClientId.setText(clientId);
                etClientSecret.setText(clientSecret);
            }
        });

        btConfirm.setOnClickListener(v -> {
            String phone = etPhone.getText().toString();
            if (isMobileNum(phone)) {
                sdkHelper.loginByMsgCode(phone, etMsgCode.getText().toString(), new ISDKLoginListener() {
                    @Override
                    public void onLoginSuccess(String userToken, String validEndTime) {
                        Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(String error) {
                        Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show();
                    }
                });
            } else {
                Toast.makeText(this, "手机号码非法", Toast.LENGTH_SHORT).show();
            }
        });

        btCancel.setOnClickListener(v -> {
            toClientWindow();
        });

        btPrevLogin.setOnClickListener(v -> {
            sdkHelper.updateToken(TokenUtil.getUserToken());
        });

        btLoginAgain.setOnClickListener(v -> {
            deviceId = null;
            toLoginWindow();
        });
        btDeviceAgain.setOnClickListener(v -> {
            deviceId = null;
            toDeviceWindow();
        });

        btDevicePrev.setOnClickListener(v -> {
            etDeviceId.setText(ConfigSet.getConfigValue(ConfigOption.OptionDeviceId));
            etTypeId.setText(ConfigSet.getConfigValue(ConfigOption.OptionTypeId));
            etModelCode.setText(ConfigSet.getConfigValue(ConfigOption.OptionModelCode));
        });

        btDeviceAuthBind.setOnClickListener(v -> {
            typeId = etTypeId.getText().toString();
            modelCode = etModelCode.getText().toString();
            deviceId = etDeviceId.getText().toString();

            if (isNumChar(typeId) && isNumChar(deviceId) && isNumChar(modelCode)) {
                sdkHelper.typeId(typeId)
                        .modelCode(modelCode)
                        .deviceId(deviceId)
                        .deviceConnect(devListener);
            } else {
                Toast.makeText(MainActivity.this, "参数格式不对", Toast.LENGTH_SHORT).show();
            }
        });

        btDeviceBind.setOnClickListener(v -> {
            if (StringUtils.isEmpty(TokenUtil.getUserToken())) {
                Toast.makeText(MainActivity.this, "未登录", Toast.LENGTH_SHORT).show();
                return;
            }
            typeId = etTypeId.getText().toString();
            modelCode = etModelCode.getText().toString();
            deviceId = etDeviceId.getText().toString();
            if (isNumChar(typeId) && isNumChar(deviceId) && isNumChar(modelCode)) {
                sdkHelper.bindDevice(TokenUtil.getUserToken(), deviceId, typeId, modelCode, new IBindDeviceListener() {
                            @Override
                            public void onSuccess(ApiDeviceInfoData device) {
                                Log.e(TAG, "bindDevice success");
                                Toast.makeText(MainActivity.this, "设备绑定成功", Toast.LENGTH_SHORT).show();
                            }

                            @Override
                            public void onError(String error) {
                                Log.e(TAG, "bindDevice failure");
                                Toast.makeText(MainActivity.this, "设备绑定失败", Toast.LENGTH_SHORT).show();
                            }
                        });
            } else {
                Toast.makeText(MainActivity.this, "参数格式不对", Toast.LENGTH_SHORT).show();
            }
        });

        btDeviceExit.setOnClickListener(v -> {
            toLoginWindow();
        });

        btWrite.setOnClickListener(v -> {
            String attribute = etAttrName.getText().toString();
            String attrValue = etAttrValue.getText().toString();
            if (isNumChar(attribute)) {
                sdkHelper.setDeviceAttribute(deviceId, attribute, attrValue);
                showLog(String.format("setDeviceAttribute: %s, %s, %s", deviceId, attribute, attrValue));
            }
        });

        btRead.setOnClickListener(v -> {
            String attribute = etAttrName.getText().toString();
            etAttrValue.setText("");
            if (isNumChar(attribute)) {
                sdkHelper.getDeviceAttribute(deviceId, attribute);
                showLog(String.format("getDeviceAttribute: %s, %s", deviceId, attribute));
            }
        });

        toClientWindow();
    }

    private void showLog(String log) {
        String text = etActionLog.getText().toString();
        StringBuilder builder = new StringBuilder(text);
        builder.append(log);
        builder.append("\n");
        etActionLog.setText(builder.toString());
    }
}